home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Commun⁄Network / RevRdist Folder / RevRdist / RevRdist src / pref.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-07-05  |  26.5 KB  |  1,215 lines  |  [TEXT/KAHL]

  1. /*
  2.  * pref.c - routines to handle preferences dialog
  3.  */
  4.  
  5. #include "RevRdist.h"
  6. #include "TransSkelProto.h"
  7. #include "Bullet Field Mgr.h"
  8.  
  9. static Boolean            cancelled;
  10. static Boolean            prefAltered = 0;
  11.  
  12. static Integer            curItem = 0;    /* current editText field */
  13.  
  14. /*
  15.  * Special keycodes
  16.  */
  17. #define    ENTER        0x03
  18. #define    BACKSPACE    0x08
  19. #define    TAB            0x09
  20. #define    RETURN        0x0d
  21. #define    CLEAR        0x1b
  22.  
  23. /*
  24.  * prefinfo - mapping among preference resource id's, Prefs[].p[] indexes,
  25.  *    and preferences dialog item numbers.
  26.  * Note that not all values apply to all entries.
  27.  */
  28. static struct prefinfo
  29. {
  30.     Integer        p_id;            /* Resource ID of preference */
  31.     Integer        p_in;            /* Item number in dialog */
  32.     StringPtr    p_nm;            /* Name of resource */
  33. } pi[] = {
  34.      { STR_ZONE,        PRF_ZONE,        0 } /* PS_ZONE */
  35.     ,{ STR_SRVR,        PRF_SRVR,        0 }    /* PS_SRVR */
  36.     ,{ STR_USER,        PRF_USER,        0 }    /* PS_USER */
  37.     ,{ STR_PASS,        PRF_PASS,        0 }    /* PS_PASS */
  38.     ,{ STR_DISTF,        PRF_DISTF,        0 }    /* PS_DISTF */
  39.     ,{ STR_MASTF,        PRF_MASTF,        0 }    /* PS_MASTF */
  40.     ,{ STR_JUNKF,        PRF_JUNKF,        0 }    /* PS_JUNKF */
  41.     ,{ JUNK_PARM,        0,                0 }    /* PS_MAX & Junking info */
  42.     ,{ TIME_INTERVAL,    PRF_INTERVAL,    0 }    /* PS_TIME */
  43.     ,{ 0,                PRF_JMIN,        0 }    /* split-out parts of junk info */
  44.     ,{ 0,                PRF_JMAX,        0 }
  45.     ,{ 0,                PRF_DMIN,        0 }
  46. };
  47.  
  48. #define    PICOUNT    (sizeof pi / sizeof (struct prefinfo))
  49.  
  50. /*
  51.  * Options to setPref()
  52.  */
  53. enum sp_action
  54. {
  55.      SP_WORKTODIALOG                /* copy P_WORK to dialog */
  56.     ,SP_DIALOGTOWORK                /* copy dialog values to P_WORK */
  57.     ,SP_CHECKONLY                    /* check if dialog and P_WORK differ */
  58. };
  59.  
  60. OSErr    str2secs(Str255, Longint *, Str255);    /* in time_cvt.c */
  61.  
  62. static void prefEvent (Integer, EventRecord *);
  63. static void prefClose (void);
  64. static void prefClobber (void);
  65. static void prefDoActivate (Integer);
  66. static OSErr prefOpen (void);
  67. static void prefSetLong (Integer, Longint);
  68. static void prefSetText (Integer, StringHandle);
  69. static pascal Boolean prefSFGfilter (ParmBlkPtr);
  70. static OSErr prefWrite (void);
  71. static void edittext (Integer, Integer, Integer);
  72. static void setPref (enum sp_action);
  73.  
  74.  
  75.  
  76. /*
  77.  *=========================================================================
  78.  * doPref () - start up preferences dialog
  79.  * exit:    PrefDialog set
  80.  *=========================================================================
  81.  */
  82. void
  83. doPref ()
  84. {
  85.  
  86.     cancelled = false;
  87.     if (Flags & PF_LOCKED)
  88.         return;
  89.     if (PrefDialog)
  90.     {
  91.         SelectWindow ((WindowPtr) PrefDialog);
  92.     }
  93.     else
  94.     {
  95.         PrefDialog =
  96.             GetNewDialog (RSRC_BASE+WIND_PREF, nil, (WindowPtr) -1L);
  97.         if (PrefDialog == nil)
  98.             return;
  99.         SkelDialog (PrefDialog, (vProcPtr)prefEvent,
  100.             (vProcPtr)prefClose, (vProcPtr)prefClobber);
  101.         BulletFieldCreate (PrefDialog, 0, 1, PRF_PASS);
  102.         setPref (SP_WORKTODIALOG);
  103.     }
  104.     ShowWindow ((WindowPtr) PrefDialog);
  105. }
  106.  
  107.  
  108.  
  109. /*
  110.  *=========================================================================
  111.  * prefClobber () - get rid of the preferences dialog resources
  112.  *=========================================================================
  113.  */
  114. void
  115. prefClobber ()
  116. {
  117.     if (PrefDialog)
  118.     {
  119.         BulletFieldDispose (PrefDialog);
  120.         DisposDialog (PrefDialog);
  121.     }
  122.     PrefDialog = nil;
  123. }
  124.  
  125.  
  126. /*
  127.  *=========================================================================
  128.  * prefClose () - exit the preferences dialog
  129.  * entry:    cancelled true if dialog closed via cancel button
  130.  * exit:    preferences (possibly) set based on final values in dialog
  131.  *=========================================================================
  132.  */
  133. void
  134. prefClose ()
  135. {
  136.  
  137.     if (! cancelled)
  138.     {
  139.         setPref (SP_DIALOGTOWORK);
  140.         prefDoFMenu (FILE_CLOSE);
  141.         if (cancelled)
  142.             return;
  143.     }
  144.     prefDoActivate (0);
  145.     cancelled = false;
  146.     SkelRmveDlog (PrefDialog);
  147. }
  148.  
  149.  
  150. /*
  151.  *=========================================================================
  152.  * prefDoActivate (flag) - handle activate/deactivate events
  153.  * entry:    flag <> 0 if activate, 0 for deactivate
  154.  *=========================================================================
  155.  */
  156. static
  157. void
  158. prefDoActivate (flag)
  159.     Integer        flag;
  160. {
  161.     MenuHandle        m;                /* handle for File menu */
  162.  
  163.     if (Flags & PF_LOCKED)
  164.         flag = 0;
  165.     m = GetMHandle (2);            /* enable/disable file-related items */
  166.     if (m)
  167.     {
  168.         if (flag)
  169.         {
  170.             EnableItem (m, FILE_OPEN);
  171.             EnableItem (m, FILE_SAVE);
  172.             EnableItem (m, FILE_SAVEAS);
  173.         }
  174.         else
  175.         {
  176.             DisableItem (m, FILE_OPEN);
  177.             DisableItem (m, FILE_SAVE);
  178.             DisableItem (m, FILE_SAVEAS);
  179.         }
  180.     }
  181.     m = GetMHandle (3);
  182.     if (m)
  183.     {
  184.         if (flag)                    /* enable/disable Edit menu */
  185.             EnableItem (m, 0);
  186.         else
  187.             DisableItem (m, 0);
  188.         DrawMenuBar ();
  189.     }
  190. }
  191.  
  192.  
  193. /*
  194.  *=========================================================================
  195.  * prefDoEMenu (itemNo) - handle Edit menu for preferences
  196.  * entry:    item = selected item number
  197.  *=========================================================================
  198.  */
  199.  
  200. void
  201. prefDoEMenu (itemNo)
  202.     Integer            itemNo;
  203. {
  204.     DialogPtr        w;
  205.  
  206.     w = (DialogPtr) PrefDialog;
  207.     switch (itemNo)
  208.     {
  209.     case EDT_CUT:
  210.         if (((DialogPeek)w)->editField != PRF_PASS-1)
  211.         {
  212.             DlgCut (w);
  213.             ZeroScrap();
  214.             TEToScrap();
  215.         }
  216.         break;
  217.     case EDT_COPY:
  218.         if (((DialogPeek)w)->editField != PRF_PASS-1)
  219.         {
  220.             DlgCopy (w);
  221.             ZeroScrap();
  222.             TEToScrap();
  223.         }
  224.         break;
  225.     case EDT_PASTE:
  226.         TEFromScrap();
  227.         DlgPaste (w);
  228.         break;
  229.     case EDT_CLEAR:
  230.         DlgDelete (w);
  231.         break;
  232.     }
  233. }
  234.  
  235.  
  236. /*
  237.  *=========================================================================
  238.  * prefDoFMenu (itemNo) - handle File menu for preferences
  239.  * entry:    item = selected item number
  240.  *=========================================================================
  241.  */
  242.  
  243. void
  244. prefDoFMenu (itemNo)
  245.     Integer            itemNo;
  246. {
  247.     cnode_t *            cn;            /* ptr to fi->f_info */
  248.     OSErr                error;
  249.     file_info_t *        fi;            /* ptr to prefs file info */
  250.     Integer                i;            /* temp */
  251.     prefs_t *            pw;            /* ptr to working prefs */
  252.     prefs_t *            pf;            /* ptr to file prefs */
  253.     Integer                ref;        /* refNum for prefs file */
  254.     Boolean                savemod;    /* initial value of p_modified */
  255.     StringHandle        sh;            /* handle to prompt, etc */
  256.     Boolean                wasset;        /* previous value of f_set */
  257.     Point                where;        /* for SF package */
  258.     CInfoPBRec            cb;
  259.     SFReply                reply;
  260.     Str255                s;            /* string temp */
  261.     SFTypeList            sftypes;
  262.  
  263.     if (!PrefDialog)
  264.         return;
  265.     fi = &File_list[FL_PREF];
  266.     cn = &fi->f_info;
  267.     pw = &Prefs[P_WORK];
  268.     pf = &Prefs[P_FILE];
  269.     wasset = fi->f_set;
  270.     cancelled = false;
  271.     Clue0 = "\pdoPrefMenu";
  272.     where.h = 100; where.v = 100;
  273.  
  274.     switch (itemNo)
  275.     {
  276.     case FILE_SAVEAS:
  277.         fi = &File_list[FL_TEMP];
  278.         cn = &fi->f_info;
  279.         freeInfo (fi);
  280.         GetWTitle (PrefDialog, s);
  281.         if (s[0] < sizeof (cn->name))
  282.             COPYPS (s, cn->name);
  283.         pw->p_modified = true;
  284.  
  285.         /* fall into */
  286.     case FILE_SAVE:
  287.         if (! wasset)
  288.             pw->p_modified = true;    /* force writing */
  289.         setPref (SP_DIALOGTOWORK);    /* copy values from dialog to work */
  290.         prefMerge (P_FILE, false);    /* copy from work to file */
  291.         if (pw->p_modified)
  292.         {
  293.             /*
  294.              * Even if we think we know about a file, check that it
  295.              * is still there, since the user might delete it while
  296.              * we aren't looking
  297.              */
  298.             if (fi->f_set)
  299.             {
  300.                 error = getInfo (cn->name, fi->f_vol, cn->parID, cn);
  301.                 if (error ||
  302.                     (cn->in.f.finfo.fdCreator != CREATOR &&
  303.                      cn->in.f.finfo.fdType != TYPE_CONT))
  304.                 {
  305.                     fi->f_set = 0;
  306.                     fi->f_vol = 0;
  307.                 }
  308.             }
  309.             if (!fi->f_set && cn->name[0] == 0)
  310.             {
  311.                 sh = (StringHandle) GetResource ('STR ', STR_PREFS);
  312.                 if (**sh < sizeof (cn->name))
  313.                     COPYPS (*sh, cn->name);
  314.                 ReleaseResource ((Handle) sh);
  315.             }
  316.             while (!fi->f_set)
  317.             {
  318.             /*
  319.              * Keep trying to save until succeed or user cancels
  320.              */
  321.                 sh = (StringHandle) GetResource ('STR ', STR_PSAVE);
  322.                 HLock ((Handle) sh);
  323.                 SFPutFile (where, *sh, cn->name, (ProcPtr) 0,
  324.                     &reply);
  325.                 HUnlock ((Handle) sh);
  326.                 ReleaseResource ((Handle) sh);
  327.                 if (reply.good == false)
  328.                 {
  329.                     cancelled = true;
  330.                     break;
  331.                 }
  332.                 SetVol (nil, reply.vRefNum);
  333.                 CreateResFile (reply.fName);
  334.                 error = ResError ();
  335.                 if (error)
  336.                 {
  337.                     if (error != dupFNErr)
  338.                     {
  339. syserr:
  340.                         ClueID = error;
  341.                         panic (false, E_FILE, "\pCreateResFile", reply.fName, nil);
  342.                         if (Quit)
  343.                         {
  344.                             Quit = false;
  345.                             break;
  346.                         }
  347.                         continue;
  348.                     }
  349.                     fi->f_vol = reply.vRefNum;
  350.                     error = getInfoByPath (reply.fName, fi);
  351.                     if (error)
  352.                         goto syserr;
  353.                     if (cn->in.f.finfo.fdCreator != CREATOR &&
  354.                         cn->in.f.finfo.fdType != TYPE_CONT)
  355.                     {
  356.                         panic (true, E_TYPE, reply.fName, nil);
  357.                         Quit = false;
  358.                         continue;
  359.                     }
  360.                 }
  361.                 else
  362.                 {
  363.                     /*
  364.                      * If we created it, we need to set its finder info
  365.                      */
  366.                     ZERO (cb);
  367.                     cb.hFileInfo.ioNamePtr = reply.fName;
  368.                     cb.hFileInfo.ioVRefNum = reply.vRefNum;
  369.                     if (error = PBGetCatInfo (&cb, false))
  370.                         goto syserr;
  371.                     cb.hFileInfo.ioDirID = 0;
  372.                     cb.hFileInfo.ioFlFndrInfo.fdType = TYPE_PREF;
  373.                     cb.hFileInfo.ioFlFndrInfo.fdCreator = CREATOR;
  374.                     if (error = PBSetCatInfo (&cb, false))
  375.                         goto syserr;
  376.                     fi->f_vol = reply.vRefNum;
  377.                     if (error = getInfoByPath (reply.fName, fi))
  378.                         goto syserr;
  379.                 }
  380.             } /* end while */
  381.             if (!fi->f_set)
  382.                 break;
  383.             /*
  384.              * Finally, open the file
  385.              */
  386.             sh = fi->f_path;
  387.             HLock ((Handle) sh);
  388.             ref = OpenRFPerm(*sh, fi->f_vol, fsRdWrPerm);
  389.             HUnlock ((Handle) sh);
  390.             if (ref == -1)
  391.             {
  392.                 ClueID = ResError ();
  393.                 panic (true, E_FILE, "\pOpenRFPerm", cn->name, nil);
  394.                 pw->p_modified = true;
  395.                 Quit = false;
  396.                 cancelled = true;
  397.                 break;
  398.             }
  399.             fi->f_ref = ref;
  400.             error = prefWrite ();
  401.             CloseResFile (ref);
  402.             fi->f_ref = 0;
  403.             if (error)
  404.             {
  405.                 ClueID = error;
  406.                 panic (true, E_SYS, "\pprefWrite", nil);
  407.                 Quit = false;
  408.                 pw->p_modified = true;
  409.                 pf->p_modified = true;
  410.                 cancelled = true;
  411.                 break;
  412.             }
  413.             pw->p_modified = false;
  414.             if (fi == &File_list[FL_TEMP])
  415.             {
  416.                 /*
  417.                  * If we used FL_TEMP, copy to FL_PREF and zap FL_TEMP
  418.                  */
  419.                 freeInfo (&File_list[FL_PREF]);
  420.                 File_list[FL_PREF] = *fi;
  421.                 ZEROAT (fi);
  422.                 fi = &File_list[FL_PREF];
  423.                 cn = &fi->f_info;
  424.             }
  425.             SetWTitle (PrefDialog, cn->name);
  426.         } /* end if modified */
  427.         break;
  428.  
  429.     case FILE_OPEN:
  430.     case FILE_CLOSE:
  431.         /*
  432.          * Check if we should save changes before closing
  433.          */
  434.         savemod = pw->p_modified;
  435.         if (pw->p_modified || (setPref (SP_CHECKONLY), pw->p_modified))
  436.         {
  437.             pw->p_modified = savemod;
  438.             GetWTitle (PrefDialog, s);
  439.             ParamText (s, nil, nil, nil);
  440.             i = CautionAlert (RSRC_BASE+ALERT_SAVE, nil);
  441.             if (i == SAVE_CANCEL)
  442.             {
  443.                 cancelled = true;
  444.                 break;
  445.             }
  446.             if (i == SAVE_YES)
  447.             {
  448.                 prefDoFMenu (FILE_SAVE);
  449.                 if (cancelled)
  450.                     break;
  451.             }
  452.         }
  453.         pw->p_modified = false;
  454.         pf->p_modified = false;
  455.         if (fi->f_set && fi->f_ref)
  456.             CloseResFile (fi->f_ref);
  457.         fi->f_ref = 0;
  458.         fi->f_set = false;
  459.         if (itemNo != FILE_OPEN)
  460.             break;
  461.  
  462.         /*
  463.          * Continue with opening file
  464.          */
  465.         sftypes[0] = TYPE_PREF;
  466.         sftypes[1] = TYPE_CONT;
  467.         sftypes[2] = 'APPL';
  468.         SFGetFile (where, "\p", (FileFilterProcPtr)prefSFGfilter, 3, sftypes,
  469.                     (ProcPtr)nil, &reply);
  470.         if (reply.good == false)
  471.             break;
  472.         fi->f_vol = reply.vRefNum;
  473.         error = getInfoByPath (reply.fName, fi);
  474.         if (!error)
  475.             error = prefFFetch (fi);
  476.         if (!error)
  477.         {
  478.             prefMerge (P_WORK, false);
  479.             setPref (SP_WORKTODIALOG);
  480.         }
  481.         if (error)
  482.         {
  483.             ClueID = error;
  484.             panic (false, E_FILE, "\pOpen", reply.fName, nil);
  485.             Quit = false;
  486.             fi->f_set = false;
  487.         }
  488.         break;
  489.     } /* end itemNo switch */
  490.     if (cancelled)
  491.         Quit = false;
  492. }
  493.  
  494.  
  495. /*
  496.  *=========================================================================
  497.  * prefEvent (itemNo, theEvent) - handle events in preferences dialog
  498.  * entry:    itemNo = the item number in dialog
  499.  *            theEvent = ptr to event record significant to dialog
  500.  *=========================================================================
  501.  */
  502. void
  503. prefEvent (itemNo, theEvent)
  504.     Integer            itemNo;
  505.     EventRecord *    theEvent;
  506. {
  507.     Integer            key;            /* key character or code */
  508.  
  509.     switch (theEvent->what)
  510.     {
  511.     case mouseDown:
  512.     /*
  513.      * If we have an active editText item, close it out first
  514.      */
  515.         if (curItem)
  516.             edittext (curItem, 0, 0);
  517.         curItem = 0;
  518.         switch (itemNo)
  519.         {
  520.         case PRF_CANCEL:
  521.             cancelled = true;
  522.             prefClose ();
  523.             break;
  524.         case PRF_GO:
  525.             Pending = PA_GO;
  526.             setPref (SP_DIALOGTOWORK);
  527.             HideWindow (PrefDialog);
  528.             break;
  529.         }
  530.         break;
  531.  
  532.     case keyDown:
  533.         key = theEvent->message & 0xff;
  534.         if (key == '\t')
  535.         {
  536.             /*
  537.              * On tab, the supplied item is the *next* item, rather than
  538.              * the one just left
  539.              */
  540.             itemNo -= 2;
  541.             if (itemNo <= 2)
  542.                 itemNo = PRF_LAST;
  543.         }
  544.         edittext (itemNo, key, theEvent->modifiers);
  545.         break;
  546.  
  547.     case activateEvt:
  548.         prefDoActivate (theEvent->modifiers & activeFlag);
  549.         break;
  550.     }
  551. }
  552.  
  553.  
  554.  
  555. /*
  556.  *=========================================================================
  557.  * prefFetch (ref) - fetch preferences from resource file
  558.  * entry:    ref = fRefNum of opened resource file
  559.  * returns:    0 if no problems
  560.  *            <> 0 = system error
  561.  *            Note: a missing resource does not count as a problem
  562.  *=========================================================================
  563.  */
  564.  
  565. OSErr
  566. prefFetch (res)
  567.     Integer res;
  568. {
  569.             OSErr            error = 0;
  570.             Handle            h;
  571.             int                i;            /* Prefs[].p[] index */
  572.             Integer            id;            /* for GetResInfo */
  573.             Ptr                p;            /* temp pointer */
  574.             Integer            saveres;    /* current resource file */
  575. register    StringHandle    sh;
  576.             ResType            type;        /* for GetResInfo */
  577.             Str255            s;            /* resource name from GetResInfo */
  578.  
  579.     saveres = CurResFile ();
  580.     if (saveres != res)
  581.     {
  582.         UseResFile (res);
  583.         error = ResError ();
  584.         if (error)
  585.         {
  586.             saveres = res;
  587.             goto errout;
  588.         }
  589.     }
  590.     /*
  591.      * Free any FILE handles which differ from the WORK ones
  592.      */
  593.     for (i = 0; i < PS_MAX; i++)
  594.     {
  595.         if ((sh = Prefs[P_FILE].p[i]) != 0 && sh != Prefs[P_WORK].p[i])
  596.             DisposHandle ((Handle) sh);
  597.     }
  598.     memset ((char *)&Prefs[P_FILE], 0, sizeof (prefs_t));
  599.  
  600.     /*
  601.      * Fetch new values from resource file.  It is not an error for the
  602.      * resource to not exist.
  603.      * Also, save the name of a resource the first time we encounter one.
  604.      */
  605.     for (i = 0; i <= PS_MAX + 1; i++)
  606.     {
  607.         sh = (StringHandle) Get1Resource ((i < PS_MAX) ? 'STR ' : TYPE_LONG,
  608.                                 pi[i].p_id);
  609.         if (sh)
  610.         {
  611.             if (pi[i].p_nm == 0)
  612.             {
  613.                 GetResInfo ((Handle)sh, &id, &type, (SP)s);
  614.                 if (type == 'STR ' && s[0])
  615.                 {
  616.                     p = NewPtr ((Size) s[0] + 1);
  617.                     if (p)
  618.                         COPYPS (s, p);
  619.                     pi[i].p_nm = (StringPtr) p;
  620.                 }
  621.             }
  622.         }
  623.         else
  624.             if ((error = ResError ()) != resNotFound && error != 0)
  625.                 goto errout;
  626.         if (i < PS_MAX)
  627.         {
  628.             Prefs[P_FILE].p[i] = sh;
  629.             if (sh)
  630.                 DetachResource ((Handle) sh);
  631.         }
  632.         else
  633.         {
  634.             if (sh)
  635.             {
  636.                 switch (i)
  637.                 {
  638.                 case PS_MAX:
  639.                     BlockMove (*sh, (Ptr)&Prefs[P_FILE].p_jparam,
  640.                         sizeof (junkp_t));
  641.                     break;
  642.                 case PS_TIME:
  643.                     BlockMove (*sh, (Ptr)&Prefs[P_FILE].p_interval,
  644.                         sizeof (Prefs[P_FILE].p_interval));
  645.                     break;
  646.                 }
  647.                 ReleaseResource ((Handle) sh);
  648.             }
  649.         }
  650.     }
  651.  
  652.     error = 0;
  653.     Prefs[P_FILE].p_modified = false;
  654.     if (res != saveres)
  655.     {
  656.         UseResFile (saveres);
  657.         error = ResError ();
  658.     }
  659.     return error;
  660.  
  661. errout:
  662.     if (error == 0)
  663.         error = ResError ();
  664.     if (error == 0)
  665.         error = memFullErr;
  666.     if (res != saveres)
  667.         UseResFile (saveres);
  668.     return error;
  669. }
  670.  
  671.  
  672. /*
  673.  *=========================================================================
  674.  * prefFFetch (fi) - open preferences file and then fetch values
  675.  * entry:    fi = ptr to file_info structure describing file to open
  676.  * exit:    0 if no error, preferences fetched, file closed
  677.  *            OSErr on error
  678.  *=========================================================================
  679.  */
  680. OSErr
  681. prefFFetch (fi)
  682. register file_info_t *    fi;
  683. {
  684.     OSErr                error;
  685.     Integer                firef;            /* value from fi->f_ref */
  686.     Integer                ref;            /* file reference */
  687.  
  688.     ref = firef = fi->f_ref;
  689.     if (ref == 0)
  690.     {
  691.         HLock ((Handle) fi->f_path);
  692.         ref = OpenRFPerm (*fi->f_path, fi->f_vol, fsRdPerm);
  693.         HUnlock ((Handle) fi->f_path);
  694.         if (ref == -1)
  695.         {
  696.             error = ResError ();
  697.             if (error == 0)
  698.                 error = fnfErr;
  699.             return error;
  700.         }
  701.         fi->f_ref = ref;
  702.     }
  703.     error = prefFetch (ref);
  704.     if (firef == 0)                    /* if we opened file, close it */
  705.     {
  706.         (void) CloseResFile (ref);
  707.         fi->f_ref = 0;
  708.     }
  709.     return (error);
  710. }
  711.  
  712.  
  713.  
  714.  
  715. /*
  716.  *=========================================================================
  717.  * prefMerge (dest, merge) - copy preferences between Prefs[] elements
  718.  * entry:    dest = which element is the destination [P_WORK, P_FILE]
  719.  *            merge = false to copy in toto, true to copy only if not null
  720.  *=========================================================================
  721.  */
  722. void
  723. prefMerge (dest, merge)
  724.     pindex_t        dest;
  725.     Boolean            merge;
  726. {
  727.     int                i;
  728.     StringHandle    sh;
  729.     pindex_t        src;
  730.  
  731.     src = (dest == P_WORK) ? P_FILE : P_WORK;
  732.     Prefs[dest].p_modified = true;
  733.     if (!merge)
  734.     {
  735.         /*
  736.          * Here to copy/replace
  737.          */
  738.         for (i = 0; i < PS_MAX; i++)
  739.         {
  740.             if ((sh = Prefs[dest].p[i]) != 0 && sh != Prefs[src].p[i])
  741.                     DisposHandle ((Handle) sh);
  742.         }
  743.         Prefs[dest] = Prefs[src];
  744.         return;
  745.     }
  746.     /*
  747.      * Here to merge
  748.      */
  749.     for (i = 0; i < PS_MAX; i++)
  750.     {
  751.         if (Prefs[src].p[i] != 0)
  752.         {
  753.             if ((sh = Prefs[dest].p[i]) != 0 && sh != Prefs[src].p[i])
  754.                 DisposHandle ((Handle) sh);
  755.             Prefs[dest].p[i] = Prefs[src].p[i];
  756.         }
  757.     }
  758.     if (Prefs[src].p_interval != 0)
  759.         Prefs[dest].p_interval = Prefs[src].p_interval;
  760.     if (Prefs[src].p_jparam.min != 0)
  761.         Prefs[dest].p_jparam.min = Prefs[src].p_jparam.min;
  762.     if (Prefs[src].p_jparam.max != 0)
  763.         Prefs[dest].p_jparam.max = Prefs[src].p_jparam.max;
  764.     if (Prefs[src].p_jparam.space != 0)
  765.         Prefs[dest].p_jparam.space = Prefs[src].p_jparam.space;
  766. }
  767.  
  768.  
  769.  
  770. /*
  771.  *=========================================================================
  772.  * prefSetLong(itemNo, value) - set pref dialog item value from long integer
  773.  * entry:    itemNo = dialog item number
  774.  *            value = new value
  775.  *=========================================================================
  776.  */
  777. void
  778. prefSetLong (itemNo, value)
  779.     Integer        itemNo;
  780.     Longint        value;
  781. {
  782.     Handle        item;
  783.     Integer        itemType;
  784.     Rect        r;
  785.     Str255        st;
  786.  
  787.     itemType = -1;
  788.     GetDItem (PrefDialog, itemNo, &itemType, &item, &r);
  789.     if (itemType == editText)
  790.     {
  791.         if ((itemNo != PRF_INTERVAL
  792.           && itemNo != PRF_JMIN
  793.           && itemNo != PRF_JMAX)
  794.          || str2secs (NULL, &value, st))
  795.             NumToString (value, (SP) st);
  796.         SetIText (item, (SP) st);
  797.     }
  798. }
  799.  
  800.  
  801.  
  802. /*
  803.  *=========================================================================
  804.  * prefSetText (itemNo, sh) - set pref dialog value from handle
  805.  * entry:    itemNo = item number to change
  806.  *            sh = handle to string containing new value
  807.  *=========================================================================
  808.  */
  809. void
  810. prefSetText (itemNo, sh)
  811.     Integer            itemNo;
  812.     StringHandle    sh;
  813. {
  814.     Handle        item;
  815.     Integer        itemType;
  816.     Rect        r;
  817.     SignedByte    handleState;
  818.  
  819.     itemType = -1;
  820.     GetDItem (PrefDialog, itemNo, &itemType, &item, &r);
  821.  
  822.     if (sh && *sh && itemType == editText)
  823.     {
  824.         handleState = HGetState ((Handle) sh);
  825.         HLock ((Handle) sh);
  826.         SetIText (item, *sh);
  827.         HSetState ((Handle) sh, handleState);
  828.     }
  829. }
  830.  
  831.  
  832. /*
  833.  *=========================================================================
  834.  * prefSFGfilter (pb) - filter for SFGetFile call to open existing prefs file
  835.  * entry:    pb = pointer to paramBlock with info about potential file
  836.  *=========================================================================
  837.  */
  838. pascal
  839. Boolean
  840. prefSFGfilter (pb)
  841.     ParmBlkPtr        pb;
  842. {
  843.     /*
  844.      * File must have resource fork
  845.      */
  846.     if (pb->fileParam.ioFlRLgLen == 0)
  847.         return true;
  848.     /*
  849.      * If it is application, it must be copy of RevRdist
  850.      */
  851.     if (pb->fileParam.ioFlFndrInfo.fdType == 'APPL'
  852.     &&  pb->fileParam.ioFlFndrInfo.fdCreator != CREATOR)
  853.         return true;
  854.     return false;
  855. }
  856.  
  857.  
  858.  
  859.  
  860. /*
  861.  *=========================================================================
  862.  * prefWrite () - Write FILE preferences to file
  863.  * entry:    CurResFile() is the file to write the resources to
  864.  * returns:    0 if no error, else OSErr
  865.  *=========================================================================
  866.  */
  867. OSErr
  868. prefWrite ()
  869. {
  870.     OSErr            error;
  871.     int                i;
  872.     Integer            id;                    /* resource id */
  873.     Handle            h1, h2;
  874.     Size            len;                /* needed resource size */
  875.     prefs_t *        p;                    /* ptr to Prefs[P_FILE] */
  876.     Ptr                vp;                    /* temp pointer */
  877.  
  878.     error = 0;
  879.     p = &Prefs[P_FILE];
  880.     /*
  881.      * First, write the string resources
  882.      */
  883.     for (i = 0; i < PS_MAX; i++)
  884.     {
  885.         h1 = (Handle) p->p[i];
  886.         if (h1 == 0)
  887.             continue;
  888.         id = pi[i].p_id;
  889.         h2 = Get1Resource ('STR ', id);
  890.         if (h2 == 0)
  891.         {
  892.             h2 = h1;
  893.             error = HandToHand (&h2);
  894.             if (error) goto syserr;
  895.             AddResource (h2, 'STR ', id, pi[i].p_nm);
  896.             if (error = ResError ()) goto syserr;
  897.         }
  898.         else
  899.         {
  900.             len = **h1 + 1;
  901.             SetHandleSize (h2, len);
  902.             if (error = MemError ())
  903.                 goto syserr;
  904.             COPYPS ((SP)(*h1), (SP)(*h2));
  905.             ChangedResource (h2);
  906.         }
  907.     }
  908.     /*
  909.      * Ditto for the junking parameters
  910.      */
  911.     error = 0;
  912.     for (i = PS_MAX; i <= PS_TIME; i++)
  913.     {
  914.         id = pi[i].p_id;
  915.         switch (id)
  916.         {
  917.         case JUNK_PARM:
  918.             len = sizeof (junkp_t);
  919.             vp = (Ptr)&p->p_jparam;
  920.             break;
  921.         case TIME_INTERVAL:
  922.             len = sizeof (p->p_interval);
  923.             vp = (Ptr)&p->p_interval;
  924.             break;
  925.         default:
  926.             continue;
  927.         }
  928.         h2 = Get1Resource (TYPE_LONG, id);
  929.         if (h2 == 0)
  930.         {
  931.             h2 = NewHandle (len);
  932.             if (h2 == 0)
  933.                 goto syserr;
  934.             AddResource (h2, TYPE_LONG, id, pi[i].p_nm);
  935.             if (error = ResError ()) goto syserr;
  936.         }
  937.         else
  938.         {
  939.             SetHandleSize (h2, len);
  940.         }
  941.         BlockMove (vp, *h2, len);
  942.         ChangedResource (h2);
  943.         error = ResError ();
  944.         if (error)
  945.             goto syserr;
  946.     }
  947.     Prefs[P_FILE].p_modified = false;
  948.     return error;
  949.  
  950. syserr:
  951.     if (error == 0)
  952.         error = memFullErr;
  953.     return error;
  954. }
  955.  
  956.  
  957. /*
  958.  *=========================================================================
  959.  * edittext (itemNo, key, modifiers) - handle keyDown in dialog item
  960.  * entry:    itemNo = affected item number
  961.  *            key = character code
  962.  *            modifiers = modifiers from eventRecord
  963.  *=========================================================================
  964.  */
  965. static
  966. void
  967. edittext (itemNo, key, modifiers)
  968.     Integer            itemNo;
  969.     Integer            key;
  970.     Integer            modifiers;
  971. {
  972.     Boolean            changed;        /* item string altered ? */
  973.     int                i;                /* temp */
  974.     Integer            itemType;        /* dialog item type */
  975.     Handle            item;            /* dialog item structure */
  976.     Longint            l;                /* long temp */
  977.     Rect            r;                /* needed for GetDItem */
  978.     Integer            t;                /* temp */
  979.     Str255            st;                /* string temp */
  980.  
  981.     /*
  982.      * See if it's an item we care about
  983.      */
  984.     for (i = 0; i < PICOUNT; i++)
  985.         if (pi[i].p_in == itemNo)
  986.             break;
  987.     if (i >= PICOUNT)
  988.     {
  989.         curItem = 0;
  990.         return;                        /* don't care */
  991.     }
  992.     if (key == BACKSPACE && modifiers & shiftKey)
  993.         key = CLEAR;
  994.     GetDItem (PrefDialog, itemNo, &itemType, &item, &r);
  995.     GetIText (item, (SP) st);
  996.     changed = false;
  997.     /*
  998.      * On CLEAR key, restore original value
  999.      */
  1000.     if (key == CLEAR)
  1001.     {
  1002.         prefs_t *        p;
  1003.  
  1004.         p = &Prefs[P_WORK];
  1005.         if (i < PS_MAX)
  1006.             COPYPS (*p->p[i], st);
  1007.         else
  1008.         {
  1009.             switch (itemNo)
  1010.             {
  1011.             case PRF_INTERVAL:    l = p->p_interval; break;
  1012.             case PRF_JMIN:        l = p->p_jparam.min; break;
  1013.             case PRF_JMAX:        l = p->p_jparam.max; break;
  1014.             case PRF_DMIN:        l = p->p_jparam.space; break;
  1015.             default:
  1016.                 goto skip;
  1017.             }
  1018.             if (itemNo == PRF_DMIN || str2secs (NULL, &l, st))
  1019.                 NumToString (l, st);
  1020.         }
  1021. skip:
  1022.         changed = true;
  1023.     }
  1024.     /*
  1025.      * Handle finishing with an item
  1026.      */
  1027.     if (key == ENTER || key == TAB || key == RETURN || key == 0)
  1028.     {
  1029.         if (key && st[st[0]] == key)
  1030.         {
  1031.             st[0]--;
  1032.             changed = true;
  1033.         }
  1034.         if (i >= PS_MAX)
  1035.         {
  1036.             if (itemNo == PRF_DMIN || str2secs (st, &l, st))
  1037.             {
  1038.                 StringToNum (st, &l);
  1039.                 NumToString (l, st);
  1040.             }
  1041.             changed = true;
  1042.         }
  1043.     }
  1044.     if (changed)
  1045.         SetIText (item, st);
  1046.     if (key == ENTER || key == RETURN)
  1047.     {
  1048.         itemNo += 2;
  1049.         if (itemNo > PRF_LAST)
  1050.             itemNo = PRF_SRVR;
  1051.         SelIText (PrefDialog, itemNo, 0, 32767);
  1052.     }
  1053.     if (key == CLEAR)
  1054.     {
  1055.         t = st[0];
  1056.         SelIText (PrefDialog, itemNo, t, t);
  1057.     }
  1058.     curItem = itemNo;
  1059. }
  1060.  
  1061.  
  1062.  
  1063. /*
  1064.  *=========================================================================
  1065.  * setPref (flag) - set preference variables to/from dialog contents
  1066.  * entry:    flag =    SP_WORKTODIALOG -> copy values from P_WORK to dialog
  1067.  *                    SP_DIALOGTOWORK -> copy the other way
  1068.  *                    SP_CHECKONLY -> same as SP_DIALOGTOWORK, except that
  1069.  *                        no values are changed, but p_modified is set if
  1070.  *                        any would have been changed.
  1071.  *            PrefDialog set
  1072.  * exit:    Prefs[P_WORK].p_modified possibly set
  1073.  *=========================================================================
  1074.  */
  1075. void
  1076. setPref (action)
  1077.     enum sp_action        action;
  1078. {
  1079.     OSErr                error;
  1080.     file_info_t *        fi;
  1081.     int                    i, j;            /* temp index */
  1082.     Handle                item;            /* for GetDItem */
  1083.     Integer                itemType;        /* for GetDItem */
  1084.     Boolean                modified;        /* set true if dialog value changed */
  1085.     prefs_t *            p;
  1086.     Rect                r;                /* for GetDItem */
  1087.     StringHandle        sh;
  1088.     Longint                value;            /* temp value for junking params */
  1089.     unsigned long *        vp;                /* pointer to a value */
  1090.     junkp_t                jparam;            /* copy of junking params */
  1091.     Str255                s;                /* string temp */
  1092.  
  1093.     fi = &File_list[FL_PREF];
  1094.     p = &Prefs[P_WORK];
  1095.     jparam = p->p_jparam;
  1096.     modified = false;
  1097.     if (action == SP_WORKTODIALOG)
  1098.     {
  1099.         for (i = 0; i < PICOUNT; i++)
  1100.         {
  1101.             if (i < PS_MAX)
  1102.             {
  1103.                 sh = p->p[i];
  1104.                 if (sh)
  1105.                     prefSetText (pi[i].p_in, sh);
  1106.             }
  1107.             else
  1108.             {
  1109.                 switch (pi[i].p_in)
  1110.                 {
  1111.                 case PRF_INTERVAL:value = p->p_interval;    break;
  1112.                 case PRF_JMIN:    value = jparam.min;        break;
  1113.                 case PRF_JMAX:    value = jparam.max;        break;
  1114.                 case PRF_DMIN:    value = jparam.space;    break;
  1115.                 default:
  1116.                     continue;
  1117.                 }
  1118.                 prefSetLong (pi[i].p_in, value);
  1119.             }
  1120.         }
  1121.         /*
  1122.          * Set prefs window title to file name
  1123.          */
  1124.         if (fi->f_set)
  1125.             COPYPS (fi->f_info.name, s);
  1126.         else
  1127.             COPYPS (*Untitled, s);
  1128.         SetWTitle (PrefDialog, s);
  1129.         return;
  1130.     }
  1131.     /*
  1132.      * Here for DIALOGTOWORK and CHECKONLY
  1133.      */
  1134.     for (i = 0; i < PICOUNT; i++)
  1135.     {
  1136.         j = pi[i].p_in;
  1137.         if (j)
  1138.         {
  1139.             itemType = -1;
  1140.             GetDItem (PrefDialog, pi[i].p_in, &itemType, &item, &r);
  1141.             if (itemType != editText)
  1142.                 continue;            /* should not happen */
  1143.             GetIText (item, s);
  1144.         }
  1145.         if (i < PS_MAX)
  1146.         {
  1147.             /*
  1148.              * Handle simple strings
  1149.              */
  1150.             sh = p->p[i];
  1151.             if (s[0] == 0)
  1152.             {
  1153.                 if (sh == 0 || **sh == 0)
  1154.                     continue;
  1155.             }
  1156.             if (sh)
  1157.             {
  1158.                 HLock ((Handle) sh);
  1159.                 j = RelString (*sh, s, false, true);
  1160.                 HUnlock ((Handle) sh);
  1161.             }
  1162.             else
  1163.             {
  1164.                 sh = (StringHandle) NewHandle ((Size) s[0] + 1);
  1165.                 if (sh == 0)
  1166.                     continue;
  1167.                 p->p[i] = sh;
  1168.                 j = 1;
  1169.             }
  1170.             if (j)
  1171.             {
  1172.                 if (action == SP_DIALOGTOWORK)
  1173.                 {
  1174.                     SetHandleSize ((Handle) sh, (Size) s[0] + 1);
  1175.                     if (MemError ())
  1176.                         continue;
  1177.                     COPYPS (s, *sh);
  1178.                     /*
  1179.                      * If the name of the distfile changes, mark current file
  1180.                      * info outdated.
  1181.                      */
  1182.                     if (pi[i].p_in == PRF_DISTF)
  1183.                     {
  1184.                         File_list[FL_DIST].f_set = 0;
  1185.                     }
  1186.                 }
  1187.                 modified = true;
  1188.             }
  1189.         }
  1190.         else
  1191.         {
  1192.             switch (j)
  1193.             {
  1194.             case PRF_INTERVAL:vp = &p->p_interval;        break;
  1195.             case PRF_JMIN:    vp = &jparam.min;        break;
  1196.             case PRF_JMAX:    vp = &jparam.max;        break;
  1197.             case PRF_DMIN:    vp = &jparam.space;        break;
  1198.             default:
  1199.                 continue;
  1200.             }
  1201.             if (j == PRF_DMIN || str2secs (s, &value, NULL))
  1202.                 StringToNum (s, &value);
  1203.             if ((unsigned long) value != *vp)
  1204.             {
  1205.                 if (action == SP_DIALOGTOWORK)
  1206.                     *vp = value;
  1207.                 modified = true;
  1208.             }
  1209.         }
  1210.     }
  1211.     if (action == SP_DIALOGTOWORK)
  1212.         p->p_jparam = jparam;
  1213.     if (modified)
  1214.         p->p_modified = true;
  1215. }